// eslint-disable-next-line max-classes-per-file
import { findIndex, forEach, get, includes } from 'lodash'
import { BORDER_IMG } from '@/utils/constant'
import { cleanRequestAnimationFrameTimeOut, requestAnimationFrameTimeOut } from '@/utils/utils'
import { rotationMap } from '@/utils/attr'

function controlDom(el, display) {
  el.style.display = display
}

function getDom(el) {
  return document.querySelector(el)
}

/**
 * 图片轮播
 * @param {[type]} el   [对象]
 * @param {[type]} opts [参数]
 *
 *
 */
export class CanvasSlider {
  constructor(opts) {
    const { data = {}, canvasEl, componentWrapEl } = opts
    const { width = 200, height = 200, type = 1, id = '', srcGroup = [], rotation = 0 } = data
    this.componentWrapEl = componentWrapEl
    this.canvasEl = canvasEl
    // 区域数据
    this.initData = data
    // 画布ID
    // this.canvasElId = opts.canvasElId;
    // 画布实例对象
    this.ctx = null
    // 进场轮播特效：
    // 静止显示 0、随机99、左右擦除 10、上下擦除13、
    // 百叶窗左右11、百叶窗上下12、
    // 随机线条14、普通、菱形16、轮子17、劈裂18、
    // 切入19、棋盘20、扇形展开21、十字形扩展22、盒装23、向内溶解24
    //
    // 旧设备：
    // 6 无、0 随机、1 左右、2 百叶窗左右
    // 3 百叶窗上下、4 上下、5 随机线条
    //
    // this.sliderEnterType = Number(sliderEnterType)
    // 退场轮播特效：
    // this.sliderQuitType = Number(sliderQuitType)
    // 画布宽
    this.canvasWidth = width
    // 画布高
    this.canvasHeight = height
    // 素材列表
    // this.picList = srcGroup
    // 播放素材 index
    this.playIndex = 0
    // 当前动画状态  进场 0  退场 1
    this.animationStatus = 0
    // 当前已经加载成功的 img
    this.img = null
    // 记录动画播放数据
    this.animData = {
      runNum: 0,
      runNumB: 0,
      // 随机线条
      runLines: [],
      runObj: null,
      // 棋盘
      evenRacts: [],
      ractsMaxNum: 0,
      evenMaxNum: 0,
      // 棋盘
      oddRacts: [],
      oddMaxNum: 0,
      // 向内溶解 时间
      runTime: 1,
    }
    // 计时器
    this.setTimeObj = null
    // 停留计时器
    this.setInterObj = null
    // 区域类型
    this.type = opts.type
    // 区域类型
    this.id = opts.id
    // 进场特效时长 (毫秒)
    this.picStyleInTime = 5
    // 退场特效时长 (毫秒)
    this.picStyleOutTime = 5
    // 停留时间
    this.pauseTime = 5
    // 混播
    // this.video = document.getElementById(videoId)
    // this.videoWrap = $(`#${videoId}`).parents('.video')
    // this.video = videojs(opts.videoId);
    // this.beginTime = 0;
    // 特效值数组
    //        this.effectVal = [10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24];
    // 内码630 added by wagnwl at 20241207
    this.effectVal = [10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 630]
    this.videoEndFn = null
    this.videoErrFn = null
    this.rotation = rotationMap[Number(rotation)]
  }

  init() {
    const { componentWrapEl, canvasEl } = this
    const offsetWidth = componentWrapEl.offsetWidth
    const offsetHeight = componentWrapEl.offsetHeight

    this.canvasWidth = offsetWidth
    this.canvasHeight = offsetHeight

    this.ctx = canvasEl.getContext('2d')

    canvasEl.width = offsetWidth
    canvasEl.height = offsetHeight

    // // 2.2 画布中心点(也是起始点)平移至中心(0,0)->(x,y)
    // ctx.translate(canvasWidth / 2, ccanvasHeight / 2);
    // // 2.3 画布旋转90°
    // this.ctx.rotate(90 * Math.PI / 180);

    // 开始播放动画
    this.animation()

    // if (this.video) {
    //   if (this.videoEndFn === null || this.videoErrFn === null) {
    //     this.videoEndFn = this.listenVideoEnd.bind(this)
    //     this.videoErrFn = this.listenVideoErr.bind(this)
    //   }
    //
    //   this.video.removeEventListener('ended', this.videoEndFn)
    //   this.video.removeEventListener('error', this.videoErrFn)
    //
    //   this.video.addEventListener('ended', this.videoEndFn)
    //   this.video.addEventListener('error', this.videoErrFn)
    // }
  }

  /**
   * 视频结束回调
   * @return {[type]} [description]
   */
  listenVideoEnd() {
    this.video.currentTime = 0
    this.nextSlider()
  }

  /**
   * 监听视频报错
   */
  listenVideoErr() {
    this.video.pause()
    //
    // $(this.video).next().text($.i18n.prop('util.editer.videonolook')).show()
    // this.setTimeObj = setTimeout(function () {
    //   cleanRequestAnimationFrameTimeOut(this.setTimeObj)
    //
    //   $(this.video).next().hide()
    //
    //   this.nextSlider()
    // }, 2000)
  }

  /**
   * 获取旧图片特效 对应新特效
   * 6 无   0
   * 0 随机 99
   * 1 左右 10
   * 2 百叶窗左右 11
   * 3 百叶窗上下 12
   * 4 上下 13
   * 5 随机线条 14
   * @param  {[Number | String]} val [值]
   * @return {[Number]}     [对应新特效值]
   */
  // eslint-disable-next-line class-methods-use-this
  getOldPicEffect(val) {
    const type = Number(val)
    switch (type) {
      case 6:
        return 0
      case 0:
        return 99
      case 1:
        return 10
      case 2:
        return 11
      case 3:
        return 12
      case 4:
        return 13
      case 5:
        return 14
      default:
        return val
    }
  }

  /**
   * 获取图片特效
   * @return {[type]} [description]
   */
  getItemEffect() {
    const {
      silderType: sliderType,
      pauseTime,
      srcGroup,
      picStyleIn = null,
      picStyleOut = null,
      picStyleInTime = 20,
      picStyleOutTime = 20,
    } = this.initData
    const type = this.getOldPicEffect(Number(sliderType))
    const time = Number(pauseTime)
    const { picShowTime } = get(srcGroup, `[${this.playIndex}]`) || {}
    // 进退场特效
    this.sliderEnterType = picStyleIn === null ? type : picStyleIn
    this.sliderQuitType = picStyleOut === null ? type : picStyleOut

    // 进退场时长
    this.picStyleInTime = picStyleInTime
    this.picStyleOutTime = picStyleOutTime

    // 停留时间
    this.pauseTime = picShowTime || time
  }

  /**
   * 开始动画
   * @return {[type]} []
   */
  animation() {
    const { srcGroup } = this.initData
    if (!srcGroup.length) {
      this.dispose()
      return
    }
    const { type, storagePath, src: path } = srcGroup[this.playIndex]
    const $photo = this.el
    // $video = $(this.video),
    const $videoWrap = this.videoWrap
    const $video = ''

    cleanRequestAnimationFrameTimeOut(this.setTimeObj)
    if (type === 0) {
      if ($photo) controlDom($photo, 'none')
      if ($video) controlDom($videoWrap, 'none')

      // var name = path.substring(0,path.lastIndexOf(".")),
      //     type = path.substring(path.lastIndexOf("."),path.length),
      //     srcPath = "";

      // if(type == '.mp4'){
      //    srcPath = name+"_copy.mp4";
      // }else{
      //    srcPath = name+".mp4";
      // }

      // this.video.src = sliderConstructor.setVideoPath.call(this, path)
      // this.video.load()
      // this.video.play()
    } else {
      if ($photo) controlDom($photo, 'block')
      if ($video) controlDom($videoWrap, 'none')
      this.loadingImg(
        path,
        (e) => {
          this.img = e
          this.enterSlider()
        },
        () => {
          this.clearReact()
          this.imgErrorTip()
          cleanRequestAnimationFrameTimeOut(this.setTimeObj)

          // 切换下一张图片
          requestAnimationFrameTimeOut(
            () => {
              this.nextSlider()
            },
            2000,
            (newTimer) => {
              this.setTimeObj = newTimer
            },
          )
        },
      )
    }
  }

  /**
   * 图片缺失
   * @return {[type]} [description]
   */
  imgErrorTip() {
    const text = `图片缺失:${get(this.initData, `srcGroup[${this.playIndex}].name`) || ''}`
    const ctx = this.ctx

    ctx.font = '20px "微软雅黑"'
    ctx.fillStyle = 'red'
    ctx.textBaseline = 'middle'
    ctx.fillText(text, 0, 50)
  }

  /**
   * 图片加载
   * @param  {[type]} path        [图片地址]
   * @param  {[type]} resCallBack [成功回调]
   * @param  {[type]} errCallBack [失败回调]
   * @return {[type]}             []
   */
  // eslint-disable-next-line class-methods-use-this
  loadingImg(path, resCallBack, errCallBack) {
    const img = new Image()

    img.src = path

    img.onload = () => {
      resCallBack(img)
    }

    img.onerror = (e) => {
      errCallBack(e)
    }
  }

  /**
   * 随机特效
   * @return {[Number]} [随机特效]
   */
  effectRandom() {
    let random = Math.floor(Math.random() * 13)

    return this.effectVal[random]
  }

  /**
   * 进场动画
   * @return {[type]} [description]
   */
  enterSlider() {
    // 获取图片特效
    this.getItemEffect()

    let type = Number(this.sliderEnterType)
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    let bx, by

    // 随机特效
    if (type === 99) {
      type = this.effectRandom()
    }
    // console.log('进场动画--enterSlider---', type)
    // 切换进场
    this.animationStatus = 0
    switch (type) {
      // 静止显示
      case 0:
        this.stillSlider()
        break
      // 静止显示(旧版本)
      case 6:
        this.stillSlider()
        break
      // 左右 (旧版本)
      case 1:
        this.eraseSlider()
        break
      // 百叶窗左右 (旧版本)
      case 2:
        this.animData.runNum = 0
        this.shuttersSlider()
        break
      // 百叶窗上下 (旧版本)
      case 3:
        this.animData.runNum = 0
        this.shuttersUpSlider()
        break
      // 上下 4 (旧版本)
      case 4:
        this.animData.runNum = 0
        this.eraseUpSlider()
        break
      // 随机线条 5 (旧版本)
      case 5:
        this.randomLine(0)
        this.randomSlider()
        break
      // 左右擦除 10、
      case 10:
        this.animData.runNum = 0
        this.eraseSlider()
        break
      // 上下擦除13、
      case 13:
        this.animData.runNum = 0
        this.eraseUpSlider()
        break
      // 百叶窗左右11、
      case 11:
        this.animData.runNum = 0
        this.shuttersSlider()
        break
      // 百叶窗上下12、
      case 12:
        this.animData.runNum = 0
        this.shuttersUpSlider()
        break
      // 随机线条14、
      case 14:
        this.randomLine(0)
        this.randomSlider()
        break
      // 菱形
      case 16:
        bx = Math.floor(Math.tan(45) * (canvasWidth / 2))
        by = Math.floor(Math.tan(45) * (canvasHeight / 2))

        this.animData.obj = {
          mx: -bx,
          ly: -by,
          ex: canvasWidth + bx,
          dy: canvasHeight + by,
          zx: -bx,
        }
        this.diamondSlider()
        break
      // 轮子
      case 17:
        this.animData.runNum = -90
        this.wheelSlider()
        break
      // 劈裂
      case 18:
        this.animData.runNum = 0
        this.splitSlider()
        break
      // 切入
      case 19:
        this.animData.runNum = canvasHeight
        this.cutInSlider()
        break
      // 棋盘
      case 20:
        this.animData.evenMaxNum = 0
        this.animData.oddMaxNum = 0
        this.calculationCheckerboard()
        this.checkerboardSlider()
        break
      // 扇形展开
      case 21:
        this.animData.runNum = -90
        this.animData.runNumB = 270
        this.sectorSlider()
        break
      // 十字形扩展
      case 22:
        this.animData.runNum = canvasWidth > canvasHeight ? canvasWidth : canvasHeight
        this.crossSlider()
        break
      // 盒装24、
      case 23:
        this.animData.runNum = canvasWidth
        this.animData.runNumB = canvasHeight
        this.boxedSlider()
        break
      // 向内溶解25
      case 24:
        this.randomRect()
        this.dissolveSlider()
        break
    }
  }

  /**
   * 退场动画
   * @return {[type]} [description]
   */
  quitSlider() {
    // 获取图片特效
    this.getItemEffect()

    let type = this.sliderQuitType
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    let bx, by

    // 随机特效
    if (type === 99) {
      type = this.effectRandom()
    }

    // 切换退场
    this.animationStatus = 1
    switch (type) {
      // 静止显示 0
      case 0:
        this.stillSlider()
        break
      // 静止显示 6 (旧版本)
      case 6:
        this.stillSlider()
        break
      // 左右 1 (旧版本)
      case 1:
        this.eraseSlider()
        break
      // 上下 4 (旧版本)
      case 4:
        this.animData.runNum = 0
        this.eraseUpSlider()
        break
      // 百叶窗左右 2 (旧版本)
      case 2:
        this.animData.runNum = 0
        this.shuttersSlider()
        break
      // 百叶窗上下 3 (旧版本)
      case 3:
        this.animData.runNum = 0
        this.shuttersUpSlider()
        break
      // 随机线条 5 (旧版本)
      case 5:
        this.randomLine(0)
        this.randomSlider()
        break
      // 左右擦除
      case 10:
        this.animData.runNum = canvasWidth
        this.eraseSlider()
        break
      // 上下擦除
      case 13:
        this.animData.runNum = canvasHeight
        this.eraseUpSlider()
        break
      // 百叶窗左右、
      case 11:
        this.animData.runNum = canvasWidth / 10
        this.shuttersSlider()
        break
      // 百叶窗上下
      case 12:
        this.animData.runNum = canvasHeight / 10
        this.shuttersUpSlider()
        break
      // 随机线条
      case 14:
        this.randomLine(0)
        this.randomSlider()
        break
      // 普通、
      // case 0:

      // break;
      // 菱形
      case 16:
        bx = Math.floor(Math.tan(45) * (canvasWidth / 2))
        by = Math.floor(Math.tan(45) * (canvasHeight / 2))

        this.animData.obj = {
          mx: -bx,
          ly: -by,
          ex: canvasWidth + bx,
          dy: canvasHeight + by,
          zx: -bx,
        }
        this.diamondSlider()
        break
      // 轮子
      case 17:
        this.animData.runNum = -90
        this.wheelSlider()
        break
      // 劈裂
      case 18:
        this.animData.runNum = 0
        this.splitSlider()
        break
      // 切入
      case 19:
        this.animData.runNum = 0
        this.cutInSlider()
        break
      // 棋盘
      case 20:
        this.animData.evenMaxNum = 0
        this.animData.oddMaxNum = 0
        this.calculationCheckerboard()
        this.checkerboardSlider()
        break
      // 扇形展开
      case 21:
        this.animData.runNum = -90
        this.animData.runNumB = 270
        this.sectorSlider()
        break
      // 十字形扩展、
      case 22:
        this.animData.runNum = canvasWidth > canvasHeight ? canvasWidth : canvasHeight
        this.crossSlider()
        break
      // 盒装
      case 23:
        this.animData.runNum = canvasWidth
        this.animData.runNumB = canvasHeight
        this.boxedSlider()
        break
      // 向内溶解
      case 24:
        this.randomRect()
        this.dissolveSlider()
        break
    }
  }

  /**
   * 长条形图片绘制
   * @param  {[Number]} rx [坐标x]
   * @param  {[Number]} ry [坐标y]
   * @param  {[Number]} rw [图像宽]
   * @param  {[Number]} rh [图像高]
   * @return {[type]}    [description]
   */
  longStrip(rx, ry, rw, rh) {
    let ctx = this.ctx

    ctx.beginPath()
    ctx.rect(rx, ry, rw, rh)
    ctx.save()
    ctx.clip()
    this.drawImage()
    ctx.closePath()
    ctx.restore()
  }

  /**
   * 绘制图片
   * @return {[type]} [description]
   */
  drawImage() {
    let ctx = this.ctx,
      img = this.img,
      imgWidth = img.width,
      imgHeight = img.height,
      p = this.calculate(imgWidth, imgHeight)

    if (img) {
      console.log('rotation', this.rotation)
      if (this.rotation) {
        this.drawImageRotation(ctx, img, p)
      } else {
        ctx.drawImage(img, p.px, p.py, p.pw, p.ph)
      }
    }
  }

  drawImageRotation(ctx, img, p) {
    const canvasWidth = this.canvasWidth
    const canvasHeight = this.canvasHeight
    const rotationRad = (this.rotation * Math.PI) / 180

    ctx.save()
    ctx.translate(canvasWidth / 2, canvasHeight / 2)
    ctx.rotate(rotationRad)
    ctx.drawImage(img, p.px - canvasWidth / 2, p.py - canvasHeight / 2, p.pw, p.ph)
    ctx.restore()
  }

  drawImageRotationAndOffset(ctx, img, p, offsetX, offsetY) {
    const canvasWidth = this.canvasWidth
    const canvasHeight = this.canvasHeight
    const rotationRad = (this.rotation * Math.PI) / 180

    ctx.save()
    ctx.translate(canvasWidth / 2, canvasHeight / 2)
    ctx.rotate(rotationRad)
    ctx.drawImage(img, p.px - canvasWidth / 2 + offsetX, p.py - canvasHeight / 2 + offsetY, p.pw, p.ph)
    ctx.restore()
  }

  /**
   * 停留计时器
   * @return {[type]} [description]
   */
  stayTime() {
    const itemPauseTime = get(this.initData, `srcGroup[${this.playIndex}].pauseTime`)
    const pauseTime = (itemPauseTime || this.pauseTime) * 1000

    cleanRequestAnimationFrameTimeOut(this.setInterObj)
    requestAnimationFrameTimeOut(
      () => {
        // 执行退场动画
        this.quitSlider()
      },
      pauseTime,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 移动步数
   * @return {[Object]} []
   */
  getMoveNum(customLong = 0) {
    const animTime = Number(this.getEffectAnimTime())
    const fps = 60
    const frameTime = 1000 / fps
    const totalFrames = (animTime * 1000) / frameTime

    const moveWidthNum = this.canvasWidth / totalFrames
    const moveHeightNum = this.canvasHeight / totalFrames

    return {
      moveWidthNum,
      moveHeightNum,
      customLong: customLong / totalFrames,
    }
  }

  /**
   * 百叶窗左右特效
   * @return {[type]} [description]
   */
  shuttersSlider() {
    // 平分竖线宽度
    const average = this.canvasWidth / 10
    const animationStatus = this.animationStatus
    const { customLong } = this.getMoveNum(average)
    console.log('customLong---', customLong)
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 进场
    if (animationStatus === 0) {
      // 动画结束
      if (this.animData.runNum >= average) {
        // 开启停留时间计时
        this.stayTime()
        return
      }
      this.animData.runNum += customLong
    }
    // 退场
    else if (animationStatus === 1) {
      // 画布清除
      this.clearReact()

      // 动画结束
      if (this.animData.runNum <= 0) {
        // 切换下一张图片
        this.nextSlider()

        return
      }
      this.animData.runNum -= customLong
    }

    // 图片切割长条
    for (let i = 0, len = this.canvasWidth / average; i < len; i++) {
      let rx = i * average,
        ry = 0,
        rw = this.animData.runNum,
        rh = this.canvasHeight

      this.longStrip(rx, ry, rw, rh)
    }

    requestAnimationFrameTimeOut(
      () => {
        this.shuttersSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 获取进退场时间
   * @return {[type]} [description]
   */
  getEffectAnimTime() {
    const picStyleInTime = this.picStyleInTime || 1
    const picStyleOutTime = this.picStyleOutTime || 1
    const animationStatus = this.animationStatus
    let animTime = 0

    // 进场
    if (animationStatus === 0) {
      animTime = picStyleInTime
    }
    // 退场
    else {
      animTime = picStyleOutTime
    }

    return animTime
  }

  /**
   * 静止显示
   * @return {[type]} [description]
   */
  stillSlider() {
    const ctx = this.ctx
    const img = this.img
    const animationStatus = this.animationStatus
    // *****************************************************************
    //              imgWidth = img.path[0].width,
    //              imgHeight = img.path[0].height,
    //
    //            //支持最新chrome浏览器版本 added by wangwl at 20230120
    /// /              imgWidth = img.currentTarget.width,
    /// /              imgHeight = img.currentTarget.height,
    //
    //              p = this.calculate(imgWidth, imgHeight);
    //
    //            // 画布清除
    //            this.clearReact();
    //
    //            ctx.drawImage(img.path[0], p.px, p.py, p.pw, p.ph);

    // *****************************************************************

    const imgWidth = img.width // img.path[0].width
    const imgHeight = img.height
    // 支持最新chrome浏览器版本 added by wangwl at 20230120
    //                imgWidth = img.currentTarget.width,
    //                imgHeight = img.currentTarget.height,

    const p = this.calculate(imgWidth, imgHeight)

    // console.log('this.img---------------stillSlider----', this.img.width, imgWidth)
    // 画布清除
    this.clearReact()
    // ctx.drawImage(img, p.px, p.py, p.pw, p.ph)
    this.drawImage()
    // 进场
    if (animationStatus === 0) {
      // 开启停留时间计时
      this.stayTime()
    }
    // 退场
    else if (animationStatus === 1) {
      // 切换下一张图片
      this.nextSlider()
    }
  }

  /**
   * 左右擦除
   * @return {[type]} [description]
   */
  eraseSlider() {
    const animationStatus = this.animationStatus
    const canvasWidth = this.canvasWidth
    const canvasHeight = this.canvasHeight
    let rx = canvasWidth - this.animData.runNum
    const { moveWidthNum: moveNum } = this.getMoveNum()

    this.clearReact()

    this.setTimeObj = null

    // 进场
    if (animationStatus === 0) {
      this.animData.runNum += moveNum
    }
    // 退场
    else {
      this.animData.runNum -= moveNum
      rx = 0
    }

    this.longStrip(rx, 0, this.animData.runNum, canvasHeight)

    // 进场
    if (animationStatus === 0) {
      if (this.animData.runNum >= canvasWidth) {
        this.longStrip(0, 0, canvasWidth, canvasHeight)
        this.stayTime()
        return
      }
    }
    // 退场
    else if (this.animData.runNum <= 0) {
      // 切换下一张图片
      this.nextSlider()
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.eraseSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 上下擦除
   * @return {[type]} [description]
   */
  eraseUpSlider() {
    const animationStatus = this.animationStatus
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    let ry = canvasHeight - this.animData.runNum
    const { moveHeightNum } = this.getMoveNum()

    this.clearReact()

    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 进场
    if (animationStatus === 0) {
      this.animData.runNum += moveHeightNum
    }
    // 退场
    else {
      this.animData.runNum -= moveHeightNum
      ry = 0
    }

    this.longStrip(0, ry, canvasWidth, this.animData.runNum)

    // 进场
    if (animationStatus === 0) {
      if (this.animData.runNum > canvasHeight) {
        this.animData.runNum = canvasHeight
        this.stayTime()
        return
      }
    }
    // 退场
    else if (this.animData.runNum <= 0) {
      this.animData.runNum = 0
      // 切换下一张图片
      this.nextSlider()
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.eraseUpSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 百叶窗上下
   * @return {[type]} [description]
   */
  shuttersUpSlider() {
    // 平分竖线宽度
    const average = this.canvasHeight / 10
    const animationStatus = this.animationStatus
    const { customLong } = this.getMoveNum(average)
    // const moveNum = moveHeightNum / 10

    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 进场
    if (animationStatus === 0) {
      // 动画结束
      if (this.animData.runNum >= average) {
        // 开启停留时间计时
        this.stayTime()
        return
      }
      this.animData.runNum += customLong
    }
    // 退场
    else if (animationStatus === 1) {
      // 画布清除
      this.clearReact()

      // 动画结束
      if (this.animData.runNum <= 0) {
        // 切换下一张图片
        this.nextSlider()

        return
      }
      this.animData.runNum -= customLong
    }

    // 图片切割长条
    for (let i = 0, len = this.canvasHeight / average; i < len; i++) {
      let rx = 0,
        ry = i * average,
        rw = this.canvasWidth,
        rh = this.animData.runNum

      if (animationStatus === 1) {
        ry = (i + 1) * average - rh
      }

      this.longStrip(rx, ry, rw, rh)
    }

    requestAnimationFrameTimeOut(
      () => {
        this.shuttersUpSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 菱形
   * @return {[type]} [description]
   */
  diamondSlider() {
    const animTime = this.getEffectAnimTime()
    const ctx = this.ctx
    const points = this.animData.obj
    const animationStatus = this.animationStatus
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    const halfH = canvasHeight / 2
    const halfW = canvasWidth / 2
    const frame = this.getFrame()
    const lwn = (halfW / frame) * 2.3
    const lhn = (halfH / frame) * 2.3

    points.mx += lwn
    points.ly += lhn
    points.ex -= lwn
    points.dy -= lhn
    points.zx += lwn

    this.clearReact()

    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    if (points.mx >= halfW && points.ly >= halfH) {
      points.mx = 0
      points.ly = 0
      points.ex = 0
      points.dy = 0
      points.zx = 0
    }

    // 进场
    if (animationStatus === 0) {
      // this.longStrip(0, 0, canvasWidth, canvasHeight);
      this.drawImage()
      ctx.beginPath()
      ctx.moveTo(points.mx, halfH)
      ctx.lineTo(halfW, points.ly)
      ctx.lineTo(points.ex, halfH)
      ctx.lineTo(halfW, points.dy)
      ctx.lineTo(points.zx, halfH)
      ctx.fillStyle = '#000000'
      ctx.fill()
      ctx.restore()
    }
    // 退场
    else {
      ctx.save()
      ctx.beginPath()
      ctx.moveTo(points.mx, halfH)
      ctx.lineTo(halfW, points.ly)
      ctx.lineTo(points.ex, halfH)
      ctx.lineTo(halfW, points.dy)
      ctx.lineTo(points.zx, halfH)
      ctx.clip()
      // ctx.drawImage(this.img.path[0], 0, 0, canvasWidth, canvasHeight);
      this.drawImage()
      ctx.restore()
    }

    if (points.mx === 0 && points.ly === 0) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      }
      // 退场
      else {
        // 下一张
        this.nextSlider()
      }
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.diamondSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 随机线条
   * @param  {[type]} index [数字索引]
   * @return {[type]}       [description]
   */
  randomSlider(index) {
    const runLines = this.animData.runLines
    const len = runLines.length
    const canvasWidth = this.canvasWidth
    const animationStatus = this.animationStatus

    index = index || 0

    let line = this.animData.runLines[index],
      ry = line.y,
      rh = line.h

    // 进场
    if (animationStatus === 0) {
      this.longStrip(0, ry, canvasWidth, rh)
    }
    // 退场
    else {
      // 画布清除
      this.ctx.beginPath()
      this.ctx.clearRect(0, ry, canvasWidth, rh)
    }

    index++

    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    if (len - 1 < index) {
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      } else {
        // 切换下一张图片
        this.nextSlider()
      }

      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.randomSlider(index)
      },
      this.animData.runTime,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 轮子
   * @return {[type]} [description]
   */
  wheelSlider() {
    const ctx = this.ctx
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    const halfW = canvasWidth / 2
    const halfH = canvasHeight / 2
    const r = (canvasHeight > canvasWidth ? canvasHeight : canvasWidth) * 2
    const animationStatus = this.animationStatus
    let angle = 270
    let counterclockwise = true

    // 获取动画时间（秒）
    const animTime = this.getEffectAnimTime()

    // 计算圆形周长
    const circumference = 2 * Math.PI * r

    // 计算需要移动的弧长（270度对应的弧长）
    const arcLength = (270 / 360) * circumference

    // 根据动画时间计算步长（每帧移动的长度）
    // const fps = 60
    // const totalFrames = animTime * fps
    const frame = this.getFrame()
    const lengthStep = (arcLength / frame) * 2

    // 将长度步长转换为角度步长
    // 角度步长 = (长度步长 * 360) / 周长
    const moveNum = (lengthStep * 360) / circumference

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 初始化runNum（如果未初始化）
    if (this.animData.runNum === undefined || this.animData.runNum === null) {
      this.animData.runNum = 0
    }

    this.animData.runNum += moveNum
    // 进场
    if (animationStatus === 0) {
      counterclockwise = false
      angle = -90
    }

    if (this.animData.runNum > 270) {
      this.animData.runNum = 270
    }

    ctx.save()
    ctx.beginPath()
    ctx.moveTo(halfW, halfH)
    ctx.arc(halfW, halfH, r, (angle * Math.PI) / 180, (this.animData.runNum * Math.PI) / 180, counterclockwise)
    ctx.closePath()
    ctx.clip()
    this.drawImage()
    ctx.restore()

    if (this.animData.runNum >= 270) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      }
      // 退场
      else {
        // 下一张
        this.nextSlider()
      }
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.wheelSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 劈裂
   * @return {[type]} [description]
   */
  splitSlider() {
    const ctx = this.ctx
    const animationStatus = this.animationStatus
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    let rectW = canvasWidth - this.animData.runNum
    const { moveWidthNum } = this.getMoveNum()

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    this.animData.runNum += moveWidthNum

    if (this.animData.runNum > canvasWidth) {
      rectW = 0
    }

    // 进场
    if (animationStatus === 0) {
      this.drawImage()
      ctx.rect(this.animData.runNum / 2, 0, rectW, canvasHeight)
      ctx.save()
      ctx.fillStyle = '#00000'
      ctx.fill()
      ctx.restore()
    } else {
      this.longStrip(this.animData.runNum / 2, 0, rectW, canvasHeight)
    }

    if (this.animData.runNum > canvasWidth) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      }
      // 退场
      else {
        // 下一张
        this.nextSlider()
      }
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.splitSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 切入
   * @return {[type]} [description]
   */
  cutInSlider() {
    const animationStatus = this.animationStatus
    const ctx = this.ctx
    const img = this.img
    const canvasHeight = this.canvasHeight
    const imgWidth = img.width
    const imgHeight = img.height
    const p = this.calculate(imgWidth, imgHeight)
    let py = 0
    const { moveWidthNum } = this.getMoveNum()

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 进场
    if (animationStatus === 0) {
      this.animData.runNum -= moveWidthNum
      py = this.animData.runNum + p.py

      if (this.animData.runNum <= 0) {
        py = 0
      }
    } else {
      this.animData.runNum += moveWidthNum

      py = p.py + this.animData.runNum

      if (this.animData.runNum <= -canvasHeight) {
        this.animData.runNum = -canvasHeight
      }
    }
    console.log(img, img.target)

    if (img) {
      if (this.rotation) {
        this.drawImageRotationAndOffset(ctx, img, p, 0, py - p.py)
      } else {
        ctx.drawImage(img, p.px, p.py, p.pw, p.ph)
      }
    }

    if (this.animData.runNum <= 0 && animationStatus === 0) {
      // 开启停留时间计时
      this.stayTime()
      return
    }
    if (this.animData.runNum > canvasHeight && animationStatus === 1) {
      // 下一张
      this.nextSlider()
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.cutInSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 棋盘
   * @return {[type]} [description]
   */
  checkerboardSlider() {
    const animationStatus = this.animationStatus
    const evenRacts = this.animData.evenRacts
    const oddRacts = this.animData.oddRacts
    const { customLong } = this.getMoveNum(evenRacts[0].w)
    const moveNum = customLong * 5
    console.log('evenRacts', evenRacts[0].w, moveNum)
    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    // 棋盘1  当小于最大值时
    if (this.animData.evenMaxNum < this.animData.ractsMaxNum) {
      this.animData.evenMaxNum += moveNum
    }

    if (this.animData.evenMaxNum > this.animData.ractsMaxNum) {
      this.animData.evenMaxNum = this.animData.ractsMaxNum
    }

    // 棋盘2  当棋牌1等于最大值
    if (this.animData.evenMaxNum === this.animData.ractsMaxNum) {
      if (this.animData.oddMaxNum < this.animData.ractsMaxNum) {
        this.animData.oddMaxNum += moveNum
      } else {
        this.animData.oddMaxNum = this.animData.ractsMaxNum
      }
    }

    // 棋盘数组1
    for (let i = 0, len = evenRacts.length; i < len; i++) {
      let item = evenRacts[i],
        rx = item.x,
        ry = item.y,
        rw = item.w,
        rh = item.h

      if (animationStatus === 0) {
        this.longStrip(rx, ry, this.animData.evenMaxNum, rh)
      } else {
        this.longStrip(rx + this.animData.evenMaxNum, ry, rw - this.animData.evenMaxNum, rh)
      }
    }

    // 棋盘数组2
    for (let e = 0, elen = oddRacts.length; e < elen; e++) {
      let item = oddRacts[e],
        rx = item.x,
        ry = item.y,
        rw = item.w,
        rh = item.h

      if (animationStatus === 0) {
        this.longStrip(rx, ry, this.animData.oddMaxNum, rh)
      } else {
        this.longStrip(rx + this.animData.oddMaxNum, ry, rw - this.animData.oddMaxNum, rh)
      }
    }

    // 全部播完
    if (
      this.animData.ractsMaxNum === this.animData.evenMaxNum
      && this.animData.ractsMaxNum === this.animData.oddMaxNum
    ) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      } else {
        // 下一张
        this.nextSlider()
      }
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.checkerboardSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  getFrame() {
    const animTime = Number(this.getEffectAnimTime())
    const fps = 60
    const frameTime = 1000 / fps
    return (animTime * 1000) / frameTime
  }

  /**
   * 棋盘平分
   * @return {[type]} [description]
   */
  calculationCheckerboard() {
    const canvasWidth = this.canvasWidth
    const canvasHeight = this.canvasHeight
    const averageW = Math.floor(canvasWidth / 16)
    const averageH = 10

    this.animData.ractsMaxNum = averageW
    this.animData.evenRacts = []
    this.animData.oddRacts = []

    for (let i = 0, len = canvasWidth / averageW; i < len; i++) {
      let xTotal = averageW * i

      for (let e = 0, elen = canvasHeight / averageH; e < elen; e++) {
        const obj = { x: xTotal, y: e * averageH, w: averageW, h: averageH }

        ;((i) => {
          if (i % 2 === 0) {
            if (e % 2 === 0) {
              this.animData.evenRacts.push(obj)
            } else {
              this.animData.oddRacts.push(obj)
            }
          } else if (e % 2 === 0) {
            this.animData.oddRacts.push(obj)
          } else {
            this.animData.evenRacts.push(obj)
          }
        })(i)
      }
    }
  }

  /**
   * 扇形
   * @return {[type]} [description]
   */
  sectorSlider() {
    const animTime = this.getEffectAnimTime()
    const ctx = this.ctx
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    const halfW = canvasWidth / 2
    const halfH = canvasHeight / 2
    const r = (canvasHeight > canvasWidth ? canvasHeight : canvasWidth) * 2
    const animationStatus = this.animationStatus
    let counterclockwise = true
    const frame = this.getFrame()
    const moveNum = (90 / frame) * 2.2

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    this.animData.runNum += moveNum
    this.animData.runNumB -= moveNum

    // 进场
    if (animationStatus === 0) {
      counterclockwise = true
      if (this.animData.runNum > 90) {
        this.animData.runNum = 90
      }

      if (this.animData.runNumB < 90) {
        this.animData.runNumB = 90
      }
    } else {
      counterclockwise = true
    }

    ctx.save()
    if (animationStatus === 0) {
      this.drawImage()
    }
    ctx.beginPath()
    ctx.moveTo(halfW, halfH)
    ctx.arc(
      halfW,
      halfH,
      r,
      (this.animData.runNumB * Math.PI) / 180,
      (this.animData.runNum * Math.PI) / 180,
      counterclockwise,
    )
    if (animationStatus === 0) {
      ctx.fillStyle = '#000000'
      ctx.fill()
    } else {
      ctx.clip()
      this.drawImage()
    }
    ctx.closePath()
    ctx.restore()

    if (this.animData.runNum >= 90) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      }
      // 退场
      else {
        // 下一张
        this.nextSlider()
      }
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.sectorSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 十字扩展
   * @return {[type]} [description]
   */
  crossSlider() {
    const ctx = this.ctx
    const animationStatus = this.animationStatus
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    const { moveWidthNum } = this.getMoveNum()

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    this.animData.runNum -= moveWidthNum

    if (this.animData.runNum <= 0) {
      this.animData.runNum = 0
    }

    // 进场
    if (animationStatus === 0) {
      this.drawImage()
      ctx.beginPath()
      ctx.clearRect((canvasWidth - this.animData.runNum) / 2, 0, this.animData.runNum, canvasHeight)
      ctx.clearRect(0, (canvasHeight - this.animData.runNum) / 2, canvasWidth, this.animData.runNum)
    } else {
      this.longStrip((canvasWidth - this.animData.runNum) / 2, 0, this.animData.runNum, canvasHeight)
      this.longStrip(0, (canvasHeight - this.animData.runNum) / 2, canvasWidth, this.animData.runNum)
    }

    if (this.animData.runNum <= 0) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      }
      // 退场
      else {
        // 下一张
        this.nextSlider()
      }

      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.crossSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 盒子
   * @return {[type]} [description]
   */
  boxedSlider() {
    const animationStatus = this.animationStatus
    const ctx = this.ctx
    const canvasWidth = this.canvasWidth
    const canvasHeight = this.canvasHeight
    let rx = 0
    let ry = 0
    const { moveWidthNum, moveHeightNum } = this.getMoveNum()

    this.clearReact()
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)

    this.animData.runNum -= moveWidthNum
    this.animData.runNumB -= moveHeightNum
    rx = (canvasWidth - this.animData.runNum) / 2
    ry = (canvasHeight - this.animData.runNumB) / 2

    if (this.animData.runNum <= 0 || this.animData.runNumB <= 0) {
      this.animData.runNum = 0
      this.animData.runNumB = 0
    }

    // 进场
    if (animationStatus === 0) {
      this.drawImage()
      ctx.clearRect(rx, ry, this.animData.runNum, this.animData.runNumB)
    }
    // 退场
    else {
      this.longStrip(rx, ry, this.animData.runNum, this.animData.runNumB)
    }

    // 入场动画结束  退场动画结束
    if (this.animData.runNum === 0 && this.animData.runNumB === 0) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
        return
      }

      // 下一张
      this.nextSlider()
      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.boxedSlider()
      },
      16.67,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 向内溶解
   * @return {[type]}       [description]
   */
  dissolveSlider() {
    const ctx = this.ctx
    const animationStatus = this.animationStatus
    let getNum = Math.floor(Math.random() * 20)
    const frame = this.getFrame()
    const len = this.animData.evenRacts.length
    const runTime = (getNum / frame) * 0.5
    console.log('runTime', runTime)
    if (len < getNum) {
      getNum = len
    }

    for (let i = 0; i < len; i++) {
      if (i <= getNum - 1) {
        let item = this.animData.evenRacts[i],
          rx = item.x,
          ry = item.y,
          w = item.w,
          h = item.h

        // 进场
        if (animationStatus === 0) {
          this.longStrip(rx, ry, w, h)
        } else {
          ctx.beginPath()
          ctx.clearRect(rx, ry, w, h)
        }
      }
    }

    this.animData.evenRacts.splice(0, getNum)

    if (this.animData.evenRacts.length === 0) {
      // 进场
      if (animationStatus === 0) {
        // 开启停留时间计时
        this.stayTime()
      } else {
        // 下一张
        this.nextSlider()
      }

      return
    }

    requestAnimationFrameTimeOut(
      () => {
        this.dissolveSlider()
      },
      runTime,
      (newTimer) => {
        this.setTimeObj = newTimer
      },
    )
  }

  /**
   * 下一张
   * @return {[type]} [description]
   */
  nextSlider() {
    // 切换下一张图片
    this.playIndex++

    // console.log('nextSlider------下一张', this.initData.srcGroup.length - 1 < this.playIndex)

    // 大于图片数量 切回第一张
    if (this.initData.srcGroup.length - 1 < this.playIndex) {
      this.playIndex = 0
    }

    // this.addActiveLi()
    this.animation()
  }

  /**
   * 图片等比例缩放
   * @param  {[type]} pw [图片宽度]
   * @param  {[type]} ph [图片高度]
   * @return {[type]}    [description]
   */
  calculate(pw, ph) {
    let px = 0,
      py = 0,
      // 图片显示
      picScaleType = this.initData.picScaleType,
      w = this.canvasWidth,
      h = this.canvasHeight
    // console.log('picScaleType', picScaleType)
    if (picScaleType === 0) {
      pw = w
      ph = h
    } else if (pw < w && ph < h) {
      px = 0.5 * w - 0.5 * pw
      py = 0.5 * h - 0.5 * ph
    } else if (ph / pw > h / w) {
      let uu = ph
      ph = h
      pw = (pw * h) / uu
      px = 0.5 * w - 0.5 * pw
    } else {
      let uu = pw
      pw = w
      ph = (ph * pw) / uu
      py = 0.5 * h - 0.5 * ph
    }

    return {
      px,
      py,
      pw,
      ph,
    }
  }

  /**
   * 画布清除
   * @return {[type]} [description]
   */
  clearReact() {
    // 画布清除
    this.ctx.beginPath()
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
  }

  /**
   * 随机生成线条
   * @return {[type]} [description]
   */
  randomLine(total) {
    const animTime = this.getEffectAnimTime()
    const canvasHeight = this.canvasHeight
    const initHeight = Math.round(Math.random() * 10)

    if (total === 0) {
      this.animData.runLines = []
    }

    // 随机线条储存
    this.animData.runLines.push({
      h: initHeight,
      y: total,
    })

    total += initHeight

    if (total < canvasHeight) {
      this.randomLine(total)
    } else {
      // 补齐随机线
      if (total - canvasHeight > 0) {
        this.animData.runLines.push({
          h: total - canvasHeight,
          y: total,
        })
      }
      const frame = this.getFrame()
      this.animData.runTime = (frame / this.animData.runLines.length) * 10
      this.shuffleSort(this.animData.runLines)
    }
  }

  /**
   * 随机矩形
   * @return {[type]} [description]
   */
  randomRect() {
    const animTime = this.getEffectAnimTime()
    const canvasHeight = this.canvasHeight
    const canvasWidth = this.canvasWidth
    const rectW = Math.round(canvasWidth * 0.03)
    const rectH = Math.round(canvasHeight * 0.03)
    const len = Math.round(canvasWidth / rectW)
    const elen = Math.round(canvasHeight / rectH)

    this.animData.evenRacts = []

    for (let i = 0; i < len; i++) {
      let xTotal = rectW * i

      for (let e = 0; e < elen; e++) {
        let obj = {
          x: xTotal,
          y: rectH * e,
          w: rectW,
          h: rectH,
        }

        ;((obj) => {
          this.animData.evenRacts.push(obj)
        })(obj)
      }
    }

    this.animData.runTime = Math.round((animTime / this.animData.evenRacts.length) * 10)

    this.shuffleSort(this.animData.evenRacts)
  }

  /**
   * 打乱随机线顺序
   * @param  {[type]} arr [description]
   * @return {[type]}     [description]
   */
  // eslint-disable-next-line class-methods-use-this
  shuffleSort(arr) {
    let n = arr.length

    while (n--) {
      let index = Math.floor(Math.random() * n),
        temp = arr[index]

      arr[index] = arr[n]
      arr[n] = temp
    }
  }

  /**
   * 销毁
   * @return {[type]} [description]
   */
  dispose() {
    this.clearReact()
    // 播放素材 index
    this.playIndex = 0
    // 当前动画状态  进场 0  退场 1
    this.animationStatus = 0
    cleanRequestAnimationFrameTimeOut(this.setTimeObj)
    cleanRequestAnimationFrameTimeOut(this.setInterObj)
    this.setInterObj = null
    this.setTimeObj = null
  }

  /**
   * 重新启动
   * @return {[type]} [description]
   */
  loopAgain() {
    this.init()
  }

  /**
   * 播放当前图片 列表选项选中
   */
  addActiveLi() {
    const type = this.type
    const $lis = null

    if (includes([1, 5, 6, 7, 8], type)) {
      let playIndex = this.playIndex

      // if (type === 1) {
      //   $lis = $('#photo-list li')
      // } else if (type === 5) {
      //   $lis = $('#mixed-list li')
      // }

      if ($lis.length > 0) {
        this.activeLi = $lis.eq(playIndex)
        let liId = this.activeLi.attr('data-id') * 1

        // if(this.id === liId){
        $lis.eq(playIndex).addClass('play-act').siblings().removeClass('play-act')
        // }
      }
    }
    // else if(type === 27){

    //     var itemId = this.list[this.playIndex].itemId;

    //     $('#material-tab-barrier-mixed li').removeClass('play-act');
    //     $('#material-tab-barrier-mixed li[data-mediaid="'+ itemId +'"]').addClass('play-act');

    // }
  }

  /**
   * 左侧列表显示当前播放图片
   * @return {[type]} [description]
   */
  scrollList() {
    let $li = this.activeLi

    if ($li) {
      $li.parent().animate(
        {
          scrollTop: $li.height() * this.playIndex,
        },
        600,
      )
    }
  }

  /**
   * 重置轮播
   * @return {[type]} [description]
   */
  restSlider({ data }) {
    this.initData = data
    console.log('data?.rotation', data.rotation, rotationMap[Number(data?.rotation || 0)])
    this.rotation = rotationMap[Number(data?.rotation || 0)]
    this.dispose()
    this.loopAgain()
  }
}

// 边框动画
export class Border {
  constructor(opts) {
    const { borderType, borderSpeed, borderEffect, borderSW, id, width, height, canvasDom } = opts

    this.canvasDom = canvasDom
    // 样式
    this.imgType = borderType
    // 速度
    this.speed = borderSpeed
    // 特效
    this.borderEffect = borderEffect
    // 边框显示
    this.borderSW = borderSW
    // 区域ID
    this.id = id
    // 画布
    this.ctx = null
    // 画布宽
    this.width = width
    // 画布高
    this.height = height
    // 时间
    this.times = []
    // 截图
    this.screenshotimg = ''
    this.playNum = 0
  }

  init() {
    const { borderSW, width, height, canvasDom } = this

    this.ctx = canvasDom.getContext('2d')

    if (Number(borderSW)) {
      this.drawBorder()
    } else {
      this.ctx.clearRect(0, 0, width, height)
    }
  }

  // eslint-disable-next-line class-methods-use-this
  loadingImg(path, callback) {
    let img = new Image()

    img.src = path

    img.onload = function () {
      callback(img)
    }
  }

  // 绘制
  drawBorder() {
    const { borderEffect, imgType = 0, speed } = this
    const { top = '', bottom = '', left = '', right = '' } = BORDER_IMG[imgType]
    let timeSpeed = 100 - speed * 10,
      imgTopPath = `${top}`,
      imgBottomPath = `${bottom || top}`,
      imgLeftPath = `${left}`,
      imgRightPath = `${left || right}`

    if (includes(imgType, [0, 1, 2, 4])) {
      this.loadingImg(imgTopPath, (img) => {
        let speed = 10
        let time = null
        this.drawBorderTop(img, speed)
        this.drawBorderBottom(img, speed)

        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderTop(img, speed)
              this.drawBorderBottom(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }

            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderTop(img, speed)
              this.drawBorderBottom(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
        }

        this.playNum++
        this.getScreenImg()
      })

      this.loadingImg(imgLeftPath, (img) => {
        let speed = 10
        let time = null

        this.drawBorderLeft(img, speed)
        this.drawBorderRight(img, speed)

        // 非静止
        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderLeft(img, speed)
              this.drawBorderRight(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderLeft(img, speed)
              this.drawBorderRight(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
        }

        this.playNum++
        this.getScreenImg()
      })
    } else {
      this.loadingImg(imgTopPath, (img) => {
        let speed = 10
        let time = null

        this.drawBorderTop(img, speed)

        // 非静止
        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderTop(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderTop(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
        }

        this.playNum++
        this.getScreenImg()
      })

      this.loadingImg(imgBottomPath, (img) => {
        let speed = 10
        let time = null

        this.drawBorderBottom(img, speed)

        // 非静止
        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderBottom(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }

            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderBottom(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }

            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
        }

        this.playNum++
        this.getScreenImg()
      })

      this.loadingImg(imgLeftPath, (img) => {
        let speed = 10
        let time = null

        this.drawBorderLeft(img, speed)

        // 非静止
        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderLeft(img, speed)
              this.delTimeOut(time)
              time = requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderLeft(img, speed)
              this.delTimeOut(time)
              requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }

            requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
              this.addTimeOut(newTimer)
            })
          }

          this.addTimeOut(time)
        }

        this.playNum++
        this.getScreenImg()
      })

      this.loadingImg(imgRightPath, (img) => {
        let speed = 10
        let time = null

        this.drawBorderRight(img, speed)

        // 非静止
        if (borderEffect !== 0) {
          // 旋转
          if (borderEffect === 1) {
            const loopBorderFn = () => {
              speed += 10
              this.drawBorderRight(img, speed)
              this.delTimeOut(time)
              time = requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
            }
            time = requestAnimationFrameTimeOut(loopBorderFn, timeSpeed)
          }
          // 闪烁
          else if (borderEffect === 2) {
            const loopBorderFn = () => {
              speed += 1
              this.drawBorderRight(img, speed)
              this.delTimeOut(time)
              time = requestAnimationFrameTimeOut(loopBorderFn, timeSpeed, (newTimer) => {
                this.addTimeOut(newTimer)
              })
              this.addTimeOut(time)
            }
            time = requestAnimationFrameTimeOut(loopBorderFn, timeSpeed)
          }

          this.addTimeOut(time)
        }

        this.playNum++
        this.getScreenImg()
      })
    }
  }

  // 生成图片
  getScreenImg() {
    if (this.playNum === 2) {
      this.screenshotimg = this.canvasDom.toDataURL({ format: 'image/jpg', quality: 1 })
    }
  }

  // 上边框
  drawBorderTop(img, speed) {
    const { borderEffect, width, imgType, ctx } = this
    let long = borderEffect === 1 ? width + speed : width,
      imgWidth = imgType === 9 ? 90 : 100,
      imgHeight = imgType === 9 ? 6 : 3,
      topNum = Math.ceil(long / (imgWidth / 2))

    if (borderEffect === 1) {
      ctx.clearRect(0, 0, width, imgHeight)
    }
    // 上边框
    for (let i = 0; i < topNum; i++) {
      ctx.drawImage(img, long - i * imgWidth, 0, imgWidth, imgHeight)
    }
    // 闪烁
    if (borderEffect === 2) {
      // 能被整除 就清除
      if (speed % 2 === 0) ctx.clearRect(0, 0, width, imgHeight)
    }

    ctx.restore()
  }

  // 下边框
  drawBorderBottom(img, speed) {
    const { borderEffect, imgType, height, ctx } = this
    let width = this.width,
      long = width + speed,
      imgWidth = imgType === 9 ? 80 : 100,
      imgHeight = imgType === 9 ? 6 : 3,
      bottomNum = long / imgWidth
    const bottom = height - imgHeight

    if (borderEffect === 1) {
      ctx.clearRect(0, bottom, width, imgHeight)
    }

    // 下边框
    for (let i = 0; i < bottomNum; i++) {
      ctx.drawImage(img, i * imgWidth - speed, bottom, imgWidth, imgHeight)
    }

    // 闪烁
    if (borderEffect === 2) {
      // 能被整除 就清除
      if (speed % 2 === 0) ctx.clearRect(0, bottom, width, imgHeight)
    }

    ctx.restore()
  }

  // 左边框
  drawBorderLeft(img, speed) {
    const { borderEffect, imgType, height, ctx } = this
    let long = height + speed,
      imgWidth = imgType === 9 ? 6 : 3,
      imgHeight = imgType === 9 ? 80 : 100,
      leftNum = long / imgHeight

    if (borderEffect === 1) {
      ctx.clearRect(0, 0, imgWidth, height)
    }

    for (let i = 0; i < leftNum; i++) {
      ctx.drawImage(img, 0, i * imgHeight - speed, imgWidth, imgHeight)
    }

    // 闪烁
    if (borderEffect === 2) {
      // 能被整除 就清除
      if (speed % 2 === 0) ctx.clearRect(0, 0, imgWidth, height)
    }

    ctx.restore()
  }

  // 右边框
  drawBorderRight(img, speed) {
    const { borderEffect, imgType, width, height, ctx } = this
    let long = height + speed,
      imgWidth = imgType === 9 ? 6 : 3,
      imgHeight = imgType === 9 ? 80 : 100,
      rightNum = long / (imgHeight / 2)
    const left = width - imgWidth

    if (borderEffect === 1) {
      ctx.clearRect(left, 0, imgWidth, height)
    }

    for (let i = 0; i < rightNum; i++) {
      ctx.drawImage(img, left, long - i * imgHeight, imgWidth, imgHeight)
    }

    // 闪烁
    if (borderEffect === 2) {
      // 能被整除 就清除
      if (speed % 2 === 0) ctx.clearRect(left, 0, imgWidth, height)
    }

    ctx.restore()
  }

  // 停止计时器
  stopTime() {
    console.log('停止计时器', this.times)

    for (let i = 0, len = this.times.length; i < len; i++) {
      cleanRequestAnimationFrameTimeOut(this.times[i])
    }

    this.times = []
  }

  // 销毁
  dispose() {
    this.stopTime()
    this.ctx.clearRect(0, 0, this.width, this.height)
  }

  // 修改参数并重新初始化
  setParamsToInit(opts) {
    const { borderType, borderSpeed, borderEffect, borderSW, width, height } = opts
    // 样式
    this.imgType = borderType
    // 速度
    this.speed = borderSpeed
    // 特效
    this.borderEffect = borderEffect
    // 边框显示
    this.borderSW = borderSW
    this.width = width
    this.height = height
    this.stopTime()
    this.init()
  }

  // 移除计时器
  delTimeOut(oldTime = null) {
    if (oldTime !== null) {
      const findItemIndex = findIndex(this.times, (item) => item === oldTime)
      cleanRequestAnimationFrameTimeOut(oldTime)
      this.times.splice(findItemIndex, 1)
    }
  }

  // 推入新计时器
  addTimeOut(newTime = null) {
    if (newTime !== null) {
      this.times.push(newTime)
    }
  }
}

// 字幕滚动
export class TextCanvas {
  constructor(el, opts) {
    this.el = el
    this.data = opts.data
    this.noPlay = opts.noPlay || false // 只绘制不播放
    this.canWidth = 0 // 画布宽
    this.canHeight = 0 // 画布宽
    this.canTextArrs = [] // 文字分割后的数据
    this.moveIndex = 0 // 移动到第几张
    this.time = null // 动画计时器
    this.speed = 1 // 运动速度
    this.pauseIndex = 0
    this.stopObj = null
    this.stopMove = false
    this.images = []
    this.imgLists = opts.imgLists || []

    if (!CanvasRenderingContext2D.prototype?.wrapText) {
      CanvasRenderingContext2D.prototype.wrapText = function (
        text,
        x,
        y,
        maxWidth,
        lineHeight,
        lineY,
        color,
        textAlign,
      ) {
        let textArrs = text.split('\n')
        console.log('textArrs---', text, x, y, maxWidth)
        lineHeight += 8

        for (let i = 0; i < textArrs.length; i++) {
          if (textArrs[i] !== '') {
            let words = textArrs[i].split('\n'),
              word = ''

            for (let n = 0; n < words.length; n++) {
              let testLine = `${word + words[n]} `,
                metrics = this.measureText(testLine),
                testWidth = metrics.width

              if (testWidth > maxWidth && n > 0) {
                this.fillText(word, x, y)
                word = `${words[n]} `
                y += lineHeight
              } else {
                word = testLine
              }
            }

            this.fillText(word, x, y)
            let wordWidth = this.measureText(word).width,
              drawLineX = x

            if (i !== 0 && lineY !== null) lineY += lineHeight

            if (textAlign === 'center') {
              drawLineX = x - wordWidth / 2
            } else if (textAlign === 'right') {
              drawLineX = x - wordWidth
            }
            if (lineY !== null) TextCanvas.prototype.drawline.call(null, this, wordWidth, drawLineX, lineY, color)

            y += lineHeight
          }
        }
      }
    }
  }

  init() {
    this.draw()
  }

  // 绘制
  draw() {
    this.canWidth = this.el.offsetWidth
    this.canHeight = this.el.offsetHeight
    this.canTextArrs = []

    if (this.imgLists.length > 0) {
      this.appendImgTextHtml()
    } else {
      this.detectTextSize()
      this.drawCanTextArrs()
    }

    if (!this.noPlay) {
      this.textMove()
    }
  }

  // 首尾相接拼接
  restCanFirstLastText(textArrs) {
    let width = this.canWidth,
      nowText = textArrs[0].text,
      textWidth = textArrs[0].width,
      len = Math.ceil((width - textWidth) / textWidth)

    for (let i = 0; i < len; i++) {
      nowText += nowText
      textWidth += textWidth
    }

    return [{ id: textArrs[0].id, text: nowText, width: textWidth }]
  }

  // 多行数据重置
  restCanTextAttrs() {
    let fontSize = Number(this.data.fontSize),
      height = this.canHeight,
      width = this.canWidth,
      newCanTextArrs = [],
      textHeight = 0,
      textStr = ''

    for (let i = 0, len = this.canTextArrs.length; i < len; i++) {
      let id = this.canTextArrs[i].id,
        textWidth = this.canTextArrs[i].width,
        text = this.canTextArrs[i].text

      if (textWidth > width) {
        textStr += `${text}\n`
      } else {
        textStr += text
      }

      textHeight += fontSize + 8

      if (height - textHeight < fontSize + 8 || i === len - 1) {
        newCanTextArrs.push({ id, width, text: textStr })
        textStr = ''
        textHeight = 0
      }
    }

    this.canTextArrs = newCanTextArrs
  }

  // 根据分割数组 生成画布 绘制文字
  drawCanTextArrs() {
    let itemId = this.data.id,
      height = this.canHeight,
      width = this.canWidth,
      textShow = Number(this.data.textShow),
      siderType = Number(this.data.siderType),
      loop = 0

    if (textShow !== 0) this.restCanTextAttrs()

    if (siderType === 4 || siderType === 3) this.canTextArrs = this.canTextArrs.reverse()

    for (let i = 0, len = this.canTextArrs.length; i < len; i++) {
      if (this.noPlay && i !== 0) return

      let id = this.noPlay
          ? `screen-text-canvas-${itemId}-${this.canTextArrs[i].id}-${i}`
          : `text-canvas-test${itemId}-${this.canTextArrs[i].id}-${i}`,
        loopId = id + (len === 1 && loop === 1 ? '-loop' : ''),
        canId = len === 1 && loop === 1 ? loopId : id,
        text = this.canTextArrs[i].text

      if (siderType === 9 || siderType === 2 || siderType === 4) {
        width = this.canTextArrs[i].width
      }

      const $canId = getDom(`#${canId}`)
      const $el = this.el

      if ($canId) {
        forEach($el.querySelectorAll('.moveItem'), (item) => {
          item.style.width = `${width}px`
        })
        $canId.setAttribute('width', width)
        $canId.setAttribute('height', height)
      } else {
        const moveItem = document.createElement('div')
        const itemCanvas = document.createElement('canvas')
        moveItem.className = 'moveItem'
        moveItem.style.position = 'absolute'
        moveItem.style.width = `${width}px`
        moveItem.style.height = '100%'
        itemCanvas.width = width
        itemCanvas.height = height
        itemCanvas.id = canId
        itemCanvas.style.position = 'absolute'
        itemCanvas.style.top = '0'
        itemCanvas.style.left = '0'
        moveItem.appendChild(itemCanvas)
        $el.appendChild(moveItem)
      }

      this.drawText(canId, width, height, text)

      // 数据为一条的 多循环一次
      if (len === 1 && loop === 0 && (siderType === 9 || siderType === 5 || siderType === 6)) {
        i--
        loop = 1
      }
    }
  }

  // 获取 各种字符在实际画布上的大小
  detectTextSize() {
    let canWidth = this.canWidth,
      canHeight = this.canHeight,
      text = this.data.textGroup[0].text.split(''),
      textStr = this.data.textGroup[0].text,
      textShow = this.data.textShow * 1,
      siderType = this.data.siderType * 1,
      rtnParams = {}

    // cnText = '',
    // numText = '',
    // worldText ='',
    // specialText = '',
    // smWorldText = '',

    if (textStr !== '') {
      let textlong = 0,
        textStr = ''
      // matchCn = textStr.match(/[\u4e00-\u9fa50]/g),
      // matchWorld = textStr.match(/[A-Z]/g),
      // matchSmWorld = textStr.match(/[a-z]/g),
      // matchNum = textStr.match(/[0-9]/g),
      // matchSpecial = textStr.match(/[^\u4e00-\u9fa50A-z0-9]/g),
      // ;

      // if(matchCn){
      //     cnText = matchCn[0];
      // }

      // if(matchWorld){
      //     worldText = matchWorld[0];
      // }

      // if(matchNum){
      //     numText = matchNum[0];
      // }

      // if(matchSpecial){
      //     specialText = matchSpecial[0];
      // }

      // if(matchSmWorld){
      //     smWorldText = matchSmWorld[0];
      // }

      // 单行分割文字
      for (let i = 0, len = text.length; i < len; i++) {
        let textItem = text[i],
          itemLong = 0,
          id = i // new Date().getTime()+i+parseInt(Math.random()*100)

        itemLong = this.getTextSize(textItem)

        textlong += itemLong
        // 多行时 首尾相接不处理
        if (textShow === 1 || (siderType !== 9 && siderType !== 2 && siderType !== 4)) {
          if (/\n/.test(textItem)) {
            this.canTextArrs.push({ id, width: textlong, text: textStr })
            textStr = textItem
            textlong = 0
          } else {
            if (textlong >= canWidth) {
              this.canTextArrs.push({ id, width: textlong, text: textStr })
              textStr = textItem
              textlong = itemLong
            } else {
              textStr += textItem
            }

            if (i === len - 1 && textlong <= canWidth) {
              this.canTextArrs.push({ id, width: textlong, text: textStr })
            }
          }
        } else {
          textStr += textItem

          if ((siderType === 9 || siderType === 2 || siderType === 4) && i === len - 1) {
            this.canTextArrs.push({ id, width: textlong, text: textStr })
          }
        }
      }

      if (this.canTextArrs.length === 1 && siderType === 9) {
        this.canTextArrs = this.restCanFirstLastText(this.canTextArrs)
      }
    }
  }

  // 获取 中文 英文 数字 特殊字符文字宽度
  getTextSize(text) {
    if (!getDom('#test-text-size')) {
      const canvasItem = document.createElement('canvas')
      canvasItem.style.display = 'none'
      canvasItem.id = 'test-text-size'
      canvasItem.width = 500
      canvasItem.height = 500
      document.body.appendChild(canvasItem)
    }

    let canvas = getDom('#test-text-size'),
      ctx = canvas.getContext('2d'),
      data = this.data,
      fontSize = data.fontSize,
      fontWeight = data.fontWeight,
      fontStyle = data.fontStyle,
      font = '',
      fontFamily = data.fontFamily.replace('.ttf', '').replace('.ttc', '')

    // 斜体
    if (fontStyle === 'italic') {
      font += `${fontStyle} `
    } else {
      font += 'normal '
    }

    // 加粗
    if (fontWeight === 'bold') {
      font += `${fontWeight} `
    } else {
      font += 'normal '
    }

    font += `${fontSize}px ${fontFamily}`

    ctx.font = font
    ctx.fillText(text, 0, 0)

    //            const metrics = ctx.measureText(text);
    //            const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

    return ctx.measureText(text).width
  }

  // 图片文字
  appendImgTextHtml() {
    let shtml = ''

    for (let i = 0, len = this.imgLists.length; i < len; i++) {
      shtml += `<div class="moveItem" style="position: absolute;width:100%;height:100%;">\
                <img style="width:100%;height:100%;" src="/resources/${this.imgLists[i]}?t=${new Date().getTime()}" /></div>`
    }

    this.el.empty().append(shtml)
  }

  // 文字移动
  textMove() {
    let data = this.data,
      canWidth = this.canWidth,
      siderType = Number(data.siderType),
      textShow = Number(data.textShow),
      pauseTime = data.pauseTime * 1000,
      scrollSpeed = data.scrollSpeed,
      $moveItem = this.el.querySelectorAll('.moveItem'),
      itemLen = $moveItem.length,
      speed = 10 - scrollSpeed,
      move = null

    this.moveIndex = 0
    this.pauseIndex = 0

    switch (siderType) {
      // 静止显示
      case 0:
        move = () => {
          cleanRequestAnimationFrameTimeOut(this.time)
          if (itemLen - 1 < this.moveIndex) this.moveIndex = 0

          forEach($moveItem, (item, index) => {
            item.style.left = '0'
            item.style.top = '0'
            item.style.display = this.moveIndex === index ? 'block' : 'none'
          })

          this.moveIndex++
          requestAnimationFrameTimeOut(move, pauseTime, (time) => {
            this.time = time
          })
        }
        move()
        break
      // 1:向左移动    2:向左连续移动
      case 1:
      case 2:
        forEach($moveItem, (item, index) => {
          let left = 0

          if (siderType === 2 && textShow === 0) {
            left = canWidth
          } else {
            left = item.offsetWidth * (index + 1)
          }

          item.style.left = `${left}px`
        })
        move = () => {
          cleanRequestAnimationFrameTimeOut(this.time)
          this.stopObj = null
          this.stopMove = false

          if (this.pauseIndex > itemLen - 1) {
            this.pauseIndex = 0
          }

          forEach($moveItem, (item, index) => {
            const { offsetWidth: width, offsetLeft: left } = item
            let moveLeft = left - 1
            this.moveLeft = moveLeft

            if (left < width && left === 0 && this.pauseIndex === index && siderType !== 2) {
              this.stopObj = item
              this.stopMove = true
              return
            }

            if (left <= -width) {
              let left = width

              if (itemLen > 1) {
                left = width * (itemLen - 1)
              }

              if (siderType === 2) left = canWidth

              // 多行大于两个区域  保持一个画布的距离
              if (textShow === 1 && itemLen > 1) left += canWidth * (itemLen - 1)

              item.style.left = `${left - 1}px`
            } else {
              item.style.left = `${moveLeft}px`
            }
          })

          if (this.stopObj && siderType !== 2) {
            requestAnimationFrameTimeOut(
              () => {
                if (this.stopObj) this.stopObj.left = '-1px'
                move()
                this.pauseIndex++
              },
              pauseTime,
              (time) => {
                this.time = time
              },
            )

            return
          }

          requestAnimationFrameTimeOut(move, speed, (time) => {
            this.time = time
          })
        }
        move()
        break
      // 3:向右移      4.向右连续移动
      case 3:
      case 4:
        forEach($moveItem, (item, index) => {
          let left = 0

          left = -(item.offsetWidth * (index + 1))
          item.style.left = `${left}px`
        })
        move = () => {
          cleanRequestAnimationFrameTimeOut(this.time)
          this.stopObj = null
          this.stopMove = false

          if (this.pauseIndex > itemLen - 1) {
            this.pauseIndex = 0
          }

          forEach($moveItem, (item, index) => {
            const { offsetWidth: width, offsetLeft: left } = item
            let moveLeft = left + 1

            this.moveLeft = moveLeft

            if (left >= (siderType === 4 ? canWidth : width)) {
              let left = width

              if (itemLen > 1) left += left * (itemLen - 1)
              item.style.left = `${-left + 1}px`
            } else {
              item.style.left = `${moveLeft}px`
            }

            if (left === 0 && this.pauseIndex === index && siderType !== 4) {
              this.stopObj = item
              this.stopMove = true
            }
          })

          if (this.stopObj && siderType !== 4) {
            requestAnimationFrameTimeOut(
              () => {
                if (this.stopObj) this.stopObj.left = '1px'
                move()
                this.pauseIndex++
              },
              pauseTime,
              (time) => {
                this.time = time
              },
            )

            return
          }

          requestAnimationFrameTimeOut(move, speed, (time) => {
            this.time = time
          })
        }
        move()
        break
      // 首尾相接
      case 9:
        forEach($moveItem, (item, index) => {
          let left = 0

          if (index === 0) {
            left = canWidth
          } else {
            left = item.offsetWidth * index + canWidth
          }

          item.style.left = `${left}px`
        })

        move = () => {
          cleanRequestAnimationFrameTimeOut(this.time)

          if (this.pauseIndex > itemLen - 1) {
            this.pauseIndex = 0
          }

          forEach($moveItem, (item, index) => {
            const { offsetWidth: width, offsetLeft: left } = item
            let moveLeft = left - 1

            this.moveLeft = moveLeft

            if (left <= -width) {
              let left = width

              if (itemLen > 1) {
                left = width * (itemLen - 1)
              }
              item.style.left = `${left - 1}px`
            } else {
              item.style.left = `${moveLeft}px`
            }
          })

          requestAnimationFrameTimeOut(move, speed, (time) => {
            this.time = time
          })
        }

        move()
        break
      // 向上
      case 5:
        forEach($moveItem, (item, index) => {
          item.style.top = `${item.offsetHeight * (index + 1)}px`
        })

        move = () => {
          cleanRequestAnimationFrameTimeOut(this.time)

          this.stopObj = null
          this.stopMove = false

          if (this.pauseIndex > itemLen - 1) {
            this.pauseIndex = 0
          }

          forEach($moveItem, (item, index) => {
            const { offsetHeight: height, offsetTop: top } = item
            let moveTop = top - 1

            this.moveTop = moveTop

            if (top < height && top === 0 && this.pauseIndex === index && siderType !== 2) {
              this.stopObj = item
              this.stopMove = true
              return
            }

            if (top <= -height - 1) {
              let top = height

              if (itemLen > 1) {
                top = height * (itemLen - 1)
              }

              item.style.top = `${top}px`
            } else {
              item.style.top = `${moveTop}px`
            }
          })

          if (this.stopObj) {
            requestAnimationFrameTimeOut(
              () => {
                if (this.stopObj) this.stopObj.style.top = '-1px'
                move()
                this.pauseIndex += 1
              },
              pauseTime,
              (time) => {
                this.time = time
              },
            )
          } else {
            requestAnimationFrameTimeOut(move, speed, (time) => {
              this.time = time
            })
          }
        }

        move()
        break
      // 向下
      case 6:
        forEach($moveItem, (item, index) => {
          item.style.top = `${-(item.offsetHeight * (index + 1))}px`
        })

        move = () => {
          let len = $moveItem.length

          cleanRequestAnimationFrameTimeOut(this.time)

          this.stopObj = null
          this.stopMove = false

          if (this.pauseIndex > itemLen - 1) {
            this.pauseIndex = 0
          }

          forEach($moveItem, (item, index) => {
            const { offsetTop: top, offsetHeight: height } = item
            let moveTop = top + 1

            this.moveTop = moveTop

            if (top === 0 && this.pauseIndex === index) {
              this.stopObj = item
              this.stopMove = true
              return
            }

            if (top >= height - 1) {
              item.style.top = `${-height * (len - 1)}px`
            } else {
              item.style.top = `${moveTop}px`
            }
          })

          if (this.stopObj) {
            requestAnimationFrameTimeOut(
              () => {
                if (this.stopObj) this.stopObj.style.top = '1px'
                move()
                this.pauseIndex++
              },
              pauseTime,
              (time) => {
                this.time = time
              },
            )
          } else {
            requestAnimationFrameTimeOut(move, speed, (time) => {
              this.time = time
            })
          }
        }

        move()
        break
    }
  }

  // 绘制文字效果 斜体 加粗 大小 字体
  drawText(domId, width, height, text) {
    let canvas = document.getElementById(domId),
      ctx = canvas.getContext('2d'),
      parcent = 100,
      data = this.data,
      fontSize = Number(data.fontSize),
      fontColor = data.fontColor,
      fontWeight = data.fontWeight,
      fontStyle = data.fontStyle,
      textAlign = data.textAlign,
      textDecoration = data.textDecoration,
      background = data.background,
      textShow = data.textShow * 1,
      borderColoreffect = data.borderColoreffect * 1,
      fontFamily = data.fontFamily.replace('.ttf', '').replace('.ttc', ''),
      // width = this.canWidth,
      // height = this.canHeight,
      textWidth = 0,
      font = '',
      textLineY = null,
      fillTextX = 0,
      fillTextY = height / 2 + fontSize / 2,
      grd = null,
      wrapTextX = 0,
      wrapTextY = null

    // 居中 居右
    if (textAlign === 'center') {
      fillTextX = width / 2
      wrapTextX = fillTextX
    } else if (textAlign === 'right') {
      fillTextX = width
      wrapTextX = fillTextX
    }

    // 斜体
    if (fontStyle === 'italic') {
      font += `${fontStyle} `
    }

    // 加粗
    if (fontWeight === 'bold') {
      font += `${fontWeight} `
    }

    // 下划线
    if (textDecoration === 'underline') {
      textLineY = height / 2 + fontSize * (2 / 3)
      wrapTextY = fontSize / 2 + fontSize * (2 / 3)
    } else if (textDecoration === 'line-through') {
      textLineY = height / 2 + fontSize * (1 / 3)
      wrapTextY = fontSize / 2 + fontSize * (1 / 3)
    }

    let gradNum = Math.ceil(height / (fontSize + 5)) + 1, //
      gradDiff = 1 / gradNum // 渐变累加值

    if (textShow === 0) {
      gradNum = 3
      gradDiff = 0.5
    }

    // 渐变斜角
    if (borderColoreffect === 1) {
      grd = ctx.createLinearGradient(0, 0, width, height)

      for (let i = 0; i < gradNum; i++) {
        let index = i + 1,
          color = '#32ed25'

        if (index % 2) {
          color = '#ee0017'
        }

        grd.addColorStop(gradDiff * i, color)
      }

      fontColor = grd
    }
    // 渐变水平
    else if (borderColoreffect === 2) {
      grd = ctx.createLinearGradient(0, 0, width, 0)

      for (let i = 0; i < gradNum; i++) {
        let index = i + 1,
          color = '#f1ff00'

        if (index % 2) {
          color = '#11ff00'
        }

        grd.addColorStop(gradDiff * i, color)
      }

      fontColor = grd
    }
    // 渐变垂直
    else if (borderColoreffect === 3) {
      let grdY = textShow === 0 ? height / 2 - fontSize / 2 : 0

      grd = ctx.createLinearGradient(0, grdY, 0, height)

      for (let i = 0; i < gradNum; i++) {
        let index = i + 1,
          color = '#000af4'

        if (index % 2) {
          color = '#00fe00'
        }

        grd.addColorStop(gradDiff * i, color)
      }

      fontColor = grd
    }

    ctx.clearRect(0, 0, width, height)

    if (background !== '') {
      ctx.fillStyle = background
      ctx.fillRect(0, 0, width, height)
    }

    ctx.fillStyle = fontColor
    ctx.textAlign = textAlign
    ctx.font = `${font + fontSize}px ${fontFamily}` // italic

    if (textShow === 0) {
      console.log(text, fillTextX, fillTextY, `${font + fontSize}px ${fontFamily}`)
      ctx.fillText(text, fillTextX, fillTextY)
      textWidth = ctx.measureText(text).width

      let drawLineX = fillTextX

      if (textAlign === 'center') {
        drawLineX = fillTextX - textWidth / 2
      } else if (textAlign === 'right') {
        drawLineX = fillTextX - textWidth
      }

      if (textLineY !== null) this.drawline(ctx, textWidth, drawLineX, textLineY, fontColor)
    } else {
      ctx.wrapText(text, wrapTextX, fontSize, 0, fontSize, wrapTextY, fontColor, textAlign)
    }
  }

  // 下划线
  drawline(ctx, width, x, y, color) {
    ctx.beginPath()
    ctx.strokeStyle = color
    ctx.lineWidth = 2
    ctx.moveTo(x, y)
    ctx.lineTo(x + width, y)
    ctx.stroke()
  }

  // 销毁定时器
  dispose() {
    cleanRequestAnimationFrameTimeOut(this.time)
  }

  // 数据改变重新渲染
  restCanvas(data = null) {
    this.images = []

    this.dispose()

    this.el.innerHTML = ''

    if (data) {
      this.data = data
      this.imgLists = data.imgLists || []
    }

    this.draw()
  }

  // rtf图片重新渲染
  restRtfMove() {
    this.dispose()
    this.appendImgTextHtml()
    this.textMove()
  }

  // 改变data 数据
  changeCanvasData(data) {
    this.data = data
    this.restCanvas(true)
  }
}
